package chain

import (
	"context"
	"fmt"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethclient"
	"go-chain-data/global"
	"go-chain-data/models"
	"go-chain-data/utils"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"
	"log"
	"math/big"
	"strconv"
	"time"
)

// 判断一个地址是否是合约地址
func isContractAddress(address string) (bool, error) {
	addr := common.HexToAddress(address)
	code, err := global.EthRpcClient.CodeAt(context.Background(), addr, nil) // 获取地址对应的合约代码
	if err != nil {
		return false, err
	}

	return len(code) > 0, nil // 如果合约代码长度大于0，则说明是合约地址
}

func getLast() models.ScanConfig {
	var result models.ScanConfig
	scanClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("scan_config")
	filter := bson.D{{"rpcUrl", global.BlockChainConfig.RpcUrl}, {"chainId", global.BlockChainConfig.Id}, {"chainName", global.BlockChainConfig.Name}, {"type", global.BlockChainConfig.Type}}
	err := scanClient.FindOne(context.Background(), filter).Decode(&result)
	if err != nil {
		return models.ScanConfig{}
	}
	return result
}

func GetBlockNextId() int64 {
	BlocksClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("block_transaction_info")
	findOptions := options.FindOne()
	findOptions.SetSort(map[string]int{"_id": -1})
	var result models.BlockTransactionInfo
	err := BlocksClient.FindOne(context.Background(), bson.D{}, findOptions).Decode(&result)
	if err != nil {
		if err.Error() == "mongo: no documents in result" {
			return 1
		}
		return 0
	}
	return result.Id + 1
}

func insertMongoData(blockNumber int64, chainIdInt uint) {
	block, err := global.EthRpcClient.BlockByNumber(context.Background(), big.NewInt(blockNumber))
	//只扫有交易记录的块
	if len(block.Transactions()) == 0 {
		return
	}
	// 输出当前区块高度 与交易总数
	log.Printf("当前区块 %v ， 交易总数 %v", blockNumber, len(block.Transactions()))
	if err != nil {
		time.Sleep(time.Second)
		global.EthRpcClient, err = ReconnectRpc()
		block, err = global.EthRpcClient.BlockByNumber(context.Background(), big.NewInt(blockNumber))
		log.Println("获取块信息出错1:", err)
	}
	var data models.BlockTransactionInfo
	data.ChainName = global.BlockChainConfig.Name
	data.ChainID = chainIdInt
	data.TransactionCount = len(block.Transactions())
	data.BlockRewards = block.BaseFee().String()
	data.Difficulty = block.Difficulty().String()
	data.Extra = common.Bytes2Hex(block.Extra())
	data.ParentHash = block.ParentHash().Hex()
	data.Size = block.Size()
	data.BlockNumber = block.NumberU64()
	data.Timestamp = block.Time()
	data.BlockHash = block.Hash().Hex()
	data.Id = GetBlockNextId()
	data.LatestBlockHeight = block.NumberU64() + 1

	for _, tx := range block.Transactions() {
		fmt.Println("当前hash：", tx.Hash().Hex())
		data.Cost = tx.Cost().String()
		data.TransactionType = tx.Type()
		//if "0xd23c0a8ca21d121b525ea350b0c319c848d219a8b73c765b8a22a46f72dcad21" == tx.Hash().Hex() {
		//	fmt.Println("当前hash：", tx.Hash().Hex())
		//}
		data.TransactionHash = tx.Hash().Hex()
		from, err := types.Sender(types.LatestSignerForChainID(tx.ChainId()), tx) // 获取交易发送方
		if err != nil {
			log.Println("Failed to read the sender address", "TxHash", tx.Hash(), "err", err)
			return
		}
		data.TransactionFrom = from.String()
		// 默认为不是代币转账记录
		data.IsTokenTransfer = 0
		if tx.To() == nil { // 如果交易目标地址为空，说明是合约创建交易
			toAddress := crypto.CreateAddress(from, tx.Nonce()).Hex() // 创建合约地址
			data.Contract = toAddress
			// 设置合约地址
		} else {
			isContract, err := isContractAddress(tx.To().Hex()) // 判断目标地址是否是合约地址
			if err != nil {
				log.Println("解析合约出错:", err)
				return
			}
			if isContract {
				data.Contract = tx.To().Hex() // 设置合约地址
			} else {
				data.TransactionTo = tx.To().Hex() // 设置目标地址
			}
		}

		data.TransactionValue = tx.Value().String()
		data.GasPrice = tx.GasPrice().String()
		receipt, err := global.EthRpcClient.TransactionReceipt(context.Background(), tx.Hash())
		if err != nil {
			log.Println("获取receipt信息失败:", err)
			time.Sleep(time.Second)
			global.EthRpcClient, err = ReconnectRpc()
			receipt, err = global.EthRpcClient.TransactionReceipt(context.Background(), tx.Hash())
			log.Println("获取receipt信息失败1", err)
		}

		contractAbi := "[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0In\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1In\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount0Out\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount1Out\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"Swap\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint112\",\"name\":\"reserve0\",\"type\":\"uint112\"},{\"indexed\":false,\"internalType\":\"uint112\",\"name\":\"reserve1\",\"type\":\"uint112\"}],\"name\":\"Sync\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"constant\":true,\"inputs\":[],\"name\":\"DOMAIN_SEPARATOR\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"MINIMUM_LIQUIDITY\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"PERMIT_TYPEHASH\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"burn\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"factory\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getReserves\",\"outputs\":[{\"internalType\":\"uint112\",\"name\":\"_reserve0\",\"type\":\"uint112\"},{\"internalType\":\"uint112\",\"name\":\"_reserve1\",\"type\":\"uint112\"},{\"internalType\":\"uint32\",\"name\":\"_blockTimestampLast\",\"type\":\"uint32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token0\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_token1\",\"type\":\"address\"}],\"name\":\"initialize\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"kLast\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"mint\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"liquidity\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"price0CumulativeLast\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"price1CumulativeLast\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"skim\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount0Out\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"amount1Out\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"}],\"name\":\"swap\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"sync\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"token0\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"token1\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
		data.Status = receipt.Status
		var logsArr []models.Log
		for _, rLog := range receipt.Logs {
			if len(rLog.Topics) == 0 {
				continue
			}
			data.GasUsed = receipt.GasUsed
			var logData models.Log
			logData.Address = rLog.Address.String()
			// 获取代币信息
			symbolInfo, err := utils.CallContractMethod(rLog.Address, utils.ERC20_ABI, "symbol")
			if err != nil {
				logData.TokenName = rLog.Address.String()
			} else {
				logData.TokenName = symbolInfo[0].(string)
			}
			// 获取精度
			decimalsInfo, err := utils.CallContractMethod(rLog.Address, utils.ERC20_ABI, "decimals")
			if err != nil {
				logData.Decimals = 0
			} else {
				logData.Decimals = decimalsInfo[0].(uint8)
			}
			logData.Data = common.Bytes2Hex(rLog.Data)
			var stringArr []string
			for _, tp := range rLog.Topics {
				stringArr = append(stringArr, tp.String())
			}
			logData.Topics = stringArr

			// 判断签名
			if utils.IsTransferEvent(rLog) {
				logData.SignName = "Transfer (index_topic_1 address from, index_topic_2 address to, uint256 value)"
			} else if utils.IsApprovalEvent(rLog) {
				logData.SignName = "Approval (index_topic_1 address owner, index_topic_2 address spender, uint256 value)"
			} else if utils.IsSyncEvent(rLog) {
				logData.SignName = "Sync (uint112 reserve0, uint112 reserve1)"
			} else if utils.IsSwapV2Event(rLog) {
				logData.SignName = "Swap (index_topic_1 address sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, index_topic_2 address to)"
			} else if utils.IsSwapV3Event(rLog) {
				logData.SignName = "Swap (index_topic_1 address sender, index_topic_2 address recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick, uint128 protocolFeesToken0, uint128 protocolFeesToken1)"
			} else if utils.IsMintEvent(rLog) {
				logData.SignName = "Mint (index_topic_1 address sender, uint256 amount0, uint256 amount1)"
			} else if utils.IsDepositEvent(rLog) {
				logData.SignName = "Deposit (index_topic_1 address dst, uint256 wad)"
			} else if utils.IsBurnEvent(rLog) {
				logData.SignName = "Burn (index_topic_1 address sender, uint256 amount0, uint256 amount1, index_topic_2 address to)"
			} else {
				logData.SignName = ""
			}
			logsArr = append(logsArr, logData)

			if utils.IsTransferEvent(rLog) {
				data.IsTokenTransfer = 1
			}

			// 转账 && 是需要监听的地址 && 没有存储在watch_address_info表中
			if utils.IsTransferEvent(rLog) && models.IsWatchAddressEvent(rLog) && !models.IsExistTxHash(tx.Hash().Hex()) {
				// 将该条数据插入到MongoDB的watch_address_info集合中
				insertWatchAddressInfo(blockNumber, tx, rLog)
			}

			//是否是swap事件
			if utils.IsSwapV2Event(rLog) {
				//如果是swap事件则存储token 和pari
				err := models.SaveTokenPari(rLog, chainIdInt)
				if err != nil {
					log.Printf("failed to save token and pair: %v", err)
				}
				err = models.ParseSwapEventLogToStruct(*rLog, tx, contractAbi, chainIdInt, block.NumberU64())
				if err != nil {
					log.Printf("failed insert swap_transaction_info: %v", err)
					continue
				}
				fmt.Println("插入swap_transaction_info成功, txHash:", tx.Hash().Hex())
			}

		}
		// 防止logs字段为null
		if len(logsArr) == 0 {
			data.Logs = []models.Log{}
		} else {
			data.Logs = logsArr
		}
		err = models.CreateOne(data)
		if err != nil {
			log.Printf("failed to insert block_transaction_info: %v", err)
			return
		}
		fmt.Println("插入block_transaction_info成功, txHash:", tx.Hash().Hex())
	}
}

func SyncMongoTask() {

	latestBlock := getLast() // 获取数据库中最新的区块信息
	var startNumber int64
	if latestBlock == (models.ScanConfig{}) {
		if global.BlockNumberConfig.Number == "" {
			log.Println("yml文件未配置SettingBlockNumber字段")
			return
		}
		parseInt, err := strconv.ParseInt(global.BlockNumberConfig.Number, 10, 64)
		if err != nil {
			log.Println("blockNumber-string转int64失败:", err)
			return
		}
		startNumber = parseInt
	} else {
		startNumber = int64(latestBlock.LastBlockNumber)
		//这里处理一下 如果是上次意外退出 需要先把startNumber这块的数据删除 在扫块
		err := models.DeleteByBlockNumber(startNumber)
		wai := models.WatchAddressInfo{}
		// 删除watch_address_info表
		err = wai.DeleteByBlockNumber(startNumber)
		if err != nil {
			log.Println("删除失败", err)
			return
		}
	}
	blockNumber, err := global.EthRpcClient.BlockNumber(context.Background())
	if err != nil {
		fmt.Println("获取最新块id失败：", blockNumber)
		return
	}
	blockNumberInt64 := int64(blockNumber)
	ptr := &blockNumberInt64
	for i := startNumber; i-blockNumberInt64 <= 0; i++ {
		err := getBlockNumberAndUpdatePtr(i, ptr)
		if err != nil {
			log.Println("发生错误:", err)
			return
		}
		latestBlockNumber, err := global.EthRpcClient.BlockNumber(context.Background()) // 获取最新区块号
		if err != nil {
			log.Println("EthRpcClient.BlockNumber error : ", err)
			continue
		}
		if latestBlock.LastBlockNumber > latestBlockNumber { // 如果数据库中最新区块高度大于最新区块号，说明数据已同步
			log.Printf("latestBlock.LatestBlockHeight : %v greater than latestBlockNumber : %v \n", latestBlock.LastBlockNumber, latestBlockNumber)
			continue
		}
		var scanConfig models.ScanConfig
		chainId, err := global.EthRpcClient.ChainID(context.Background())
		if err != nil {
			log.Println("获取链id失败")
			return
		}
		chainIdInt := uint(chainId.Uint64())
		scanConfig.ChainId = chainIdInt
		scanConfig.ChainName = global.BlockChainConfig.Name
		scanConfig.RpcUrl = global.BlockChainConfig.RpcUrl
		scanConfig.LastBlockNumber = uint64(i)
		scanConfig.Type = global.BlockChainConfig.Type
		err = models.CreateScanConfig(scanConfig)
		if err != nil {
			log.Println("scan_config表insert失败:", err)
			return
		}
		insertMongoData(i, chainIdInt) // 处理当前区块信息
	}
}

func getBlockNumberAndUpdatePtr(currentNumber int64, ptr *int64) error {
	// 模拟从某处获取区块号
	blockNumber, err := global.EthRpcClient.BlockNumber(context.Background())
	//if err != nil {
	//	fmt.Println("getBlockNumberAndUpdatePtr错误：", err)
	//	return err
	//}
	// 如果获取的区块号为0，则等待一秒后重新获取 直到获取到不为0的区块号
	var client *ethclient.Client
	if blockNumber == 0 || err != nil {
		for {
			client, err = ethclient.Dial(global.BlockChainConfig.RpcUrl)
			if err == nil {
				blockNumber, err = global.EthRpcClient.BlockNumber(context.Background())
				// 如果当前区块号小于获取到的区块号，则退出循环 否则说明已经追上最新区块号 继续等待 2秒后重新获取
				if currentNumber < int64(blockNumber) {
					break
				}
			}
			log.Printf("无法连接到节点: %v", err)
			time.Sleep(2 * time.Second)
		}
		global.EthRpcClient = client
		*ptr = int64(blockNumber)
		return nil
	} else {
		for {
			if currentNumber < int64(blockNumber) {
				break
			}
			time.Sleep(2 * time.Second)
			blockNumber, err = global.EthRpcClient.BlockNumber(context.Background())
			if err != nil {
				log.Println("getBlockNumberAndUpdatePtr错误1：", err)
				return err
			}
		}
		// 更新指针指向的值
		*ptr = int64(blockNumber)
		return nil
	}
}

// ReconnectRpc 重连rpc机制
func ReconnectRpc() (*ethclient.Client, error) {
	var client *ethclient.Client
	var err error
	for {
		client, err = ethclient.Dial(global.BlockChainConfig.RpcUrl)
		if err == nil {
			break
		}
		log.Printf("无法连接到节点两秒后尝试重新连接: %v", err)
		time.Sleep(2 * time.Second)
	}
	return client, nil
}

// 插入监听记录
func insertWatchAddressInfo(blockNumber int64, tx *types.Transaction, rLog *types.Log) {
	var wai models.WatchAddressInfo
	wai.ChainName = global.BlockChainConfig.Name
	wai.BlockNumber = uint64(blockNumber)
	wai.TxHash = tx.Hash().Hex()
	wai.From = common.HexToAddress(rLog.Topics[1].Hex()).String()
	wai.To = common.HexToAddress(rLog.Topics[2].Hex()).String()
	wai.Amount = new(big.Int).SetBytes(rLog.Data).String()
	wai.Token = rLog.Address.String()
	wai.ChainId = uint(tx.ChainId().Uint64())
	wai.Verify = 0
	wai.CallBackResult = ""
	now := time.Now()
	wai.CallBackTime = now.Unix()
	wai.CallBackNumber = 10
	// 获取需要监听的地址详情
	wac, err := models.GetWatchAddressConfig(wai.From, wai.To, wai.Token)
	if err != nil {
		log.Printf("获取监听地址详情异常: %v", err)
	}
	wai.CallBackUrl = wac.CallBackUrl
	err = models.InsertWatchAddressInfo(wai)
	if err != nil {
		log.Printf("failed to insert watch_address_info: %v", err)
	}
	fmt.Println("插入watch_address_info成功, txHash:", tx.Hash().Hex())
}
